﻿using System;
using System.Collections.Generic;
using Repetition.Domain;
using System.IO;

namespace Repetition.Utilities.Conversion
{
    public class HtmlExporter
    {
        private const string HtmlInsertionMarker = "<!-- Generated HTML goes here -->";
        private const string ProblemCssMarker = "<!-- Problem CSS goes here -->";
        private const string AnswerMarker = "<!-- Answer goes here -->";
        private const string QuestionMarker = "<!-- Question goes here -->";
        private const string IdMarker = "<!-- Problem ID goes here -->";
        private const string SubjectNameMarker = "<!-- Subject name goes here -->";

        public static void ExportToFile(string filename, ICollection<Problem> problems)
        {
            using (FileStream stream = File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write))
            using (StreamWriter writer = new StreamWriter(stream))
                writer.Write(ExportToString(problems));
        }

        public static string ExportToString(ICollection<Problem> problems)
        {
            string pageTemplate = ReadFile("Templates/PageTemplate.html");
            string problemTemplate = ReadFile("Templates/ProblemTemplate.html");
            string cssTemplate = ReadFile("Templates/ProblemTemplate.css");
            string subjectTemplate = ReadFile("Templates/SubjectTemplate.html");

            return ExportToString(problems, pageTemplate, problemTemplate, cssTemplate, subjectTemplate);
        }

        public static string ExportToString(ICollection<Problem> problems, string pageTemplate, 
            string problemTemplate, string cssEntryTemplate, string subjectTemplate)
        {
            string problemHtml = "";
            string css = "";
            int id = 0;

            var sortedProblems = SortProblemsBySubject(problems);

            foreach (var pair in sortedProblems)
            {
                problemHtml += ToHtml(pair.Key, subjectTemplate); // subject title

                foreach (var problem in pair.Value)
                {
                    problemHtml += ToHtml(problem, problemTemplate, id);
                    css += ToCss(problem, cssEntryTemplate, id);
                    id++;
                }
            }

            return CreatePage(problemHtml, css, pageTemplate);
        }

        private static string CreatePage(string problemHtml, string css, string pageTemplate)
        {
            var replacements = new Dictionary<string, string>();
            
            replacements[ProblemCssMarker] = css;
            replacements[HtmlInsertionMarker] = problemHtml;

            return Template.InstantiateStringTemplate(pageTemplate, replacements);
        }

        private static IDictionary<Subject, ICollection<Problem>> SortProblemsBySubject(ICollection<Problem> problems)
        {
            var sortedProblems = new Dictionary<Subject, ICollection<Problem>>();

            foreach (var problem in problems)
            {
                foreach (var subject in problem.Subjects)
                {
                    if (sortedProblems.ContainsKey(subject))
                        sortedProblems[subject].Add(problem);
                    else
                        sortedProblems[subject] = new List<Problem>() { problem };
                }
            }

            return sortedProblems;
        }

        private static string ToHtml(Subject subject, string template)
        {
            var replacements = new Dictionary<string, string>();

            replacements[SubjectNameMarker] = subject.Name;

            return Template.InstantiateStringTemplate(template, replacements);
        }

        private static string ToHtml(Problem problem, string template, int id)
        {
            var replacements = new Dictionary<string, string>();

            replacements[QuestionMarker] = problem.Question;
            replacements[AnswerMarker] = problem.Answer;
            replacements[IdMarker] = id.ToString();

            return Template.InstantiateStringTemplate(template, replacements);
        }

        private static string ToCss(Problem problem, string template, int id)
        {
            var replacements = new Dictionary<string, string>();

            replacements[IdMarker] = id.ToString();

            return Template.InstantiateStringTemplate(template, replacements);
        }

        private static string ReadFile(string filename)
        {
            using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read))
            using (StreamReader reader = new StreamReader(stream))
                return reader.ReadToEnd();
        }
    }
}
